using System.Collections.Generic;
using System.Linq;

namespace Tycho.Parser {
    public class MergedPattern {
        public Pattern Pattern { get; private set; }
        public List<MergedPattern> MergedPatterns { get; private set; }
        
        public MergedPattern () : this (null) {
        }

        public MergedPattern (Pattern pattern) {
            MergedPatterns = new List<MergedPattern> ();
            Pattern = pattern;
        }

        public void Add (Pattern [] patterns) {
            MergedPatterns.Add (Sequence (patterns, 0));
        }

        public void Merge (Pattern [] patterns) {
            Merge (patterns, 0);
        }

        private void Merge (Pattern [] patterns, int index) {
            if (index < patterns.Length) {
                MergedPattern lastMergedPattern = MergedPatterns.LastOrDefault ();

                if (lastMergedPattern != null && lastMergedPattern.Pattern.PatternEquals(patterns[index])) {
                    lastMergedPattern.Merge (patterns, index + 1);
                } else {
                    MergedPatterns.Add (Sequence(patterns, index));
                }
            }
        }

        internal static MergedPattern Sequence (Pattern [] patterns, int index) {
            MergedPattern mergedPattern = null;
            for (int n = patterns.Length - 1; n >= index; n--) {
                var temp = new MergedPattern (patterns[n]);
                if (mergedPattern != null) {
                    temp.MergedPatterns.Add (mergedPattern);
                }
                mergedPattern = temp;
            }

            return mergedPattern;
        }

        public Node Compile () {
            Node first;
            TransitionNode last;

            if (Pattern != null) {
                NodePair nodes = Pattern.CompileNodes ();
                first = nodes.First;

                if (MergedPatterns.Count == 0) {
                    return nodes.First;
                }

                last = nodes.LastTransitionNode;
            } else {
                first = last = new TransitionNode ();
            }

            foreach (var mergedPattern in MergedPatterns) {
                last.Transitions.Add (new FreeTransition(mergedPattern.Compile ()));
            }

            return first;
        }
    }
}